package com.weight.common.Socket;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Set;

import com.weight.common.util.StringToHexUtil; 
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class SocketServer {
	//解码buffer  
    private Charset cs = Charset.forName("GBK");  
    //接受数据缓冲区  
    private static ByteBuffer sBuffer = ByteBuffer.allocate(1024);  
    //发送数据缓冲区  
    private static ByteBuffer rBuffer = ByteBuffer.allocate(1024);  
    //选择器（监听器）  
    private static Selector selector;  
    
    /** 
     * 启动socket服务，开启监听 
     * @param port 
     * @throws IOException 
     */  
    public void startSocketServer(int port){  
        try {  
            //1、新建NIO通信信道  
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();  
            //设置为通道为非阻塞  
            serverSocketChannel.configureBlocking(false);  
            
            
            //2、获取套接字  ，创建基于NIO通道的socket连接
            ServerSocket serverSocket = serverSocketChannel.socket();  
            //Socket通道 绑定端口号  
            serverSocket.bind(new InetSocketAddress(port)); 
            
            //3、打开监听器  
            selector = Selector.open();  
            //NIO通信信道绑定监听器  ，
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);  
  
            //4.监听器 实时监听，如果客户端有请求，就会进入相应的事件处理  
            while (true){  //无限循环，实时监听。
            	int num =selector.select();//select方法会一直阻塞直到有相关事件发生或超时  
            	if(num<1) continue;//本次未监听到事件
            	
            	//有监听到事件，获取监听集合，遍历处理
            	Set<SelectionKey> selectionKeys = selector.selectedKeys();//获取监听到的事件 集合
                for (SelectionKey key : selectionKeys) {  
                    handle(key);  
//                    log.info("消息:convertStringToHex:"+ StringToHexUtil.convertStringToHex(requestMsg));
                    log.info( "消息:"+key.toString());
                }  
                selectionKeys.clear();//清除处理过的事件  
            } 
            
        }catch (Exception e){  
            e.printStackTrace();  
        }  
    }  
  
    /** 
     * 处理不同的事件 
     * @param selectionKey 
     * @throws IOException 
     */  
    private void handle(SelectionKey selectionKey) throws IOException {  
        ServerSocketChannel serverSocketChannel = null;  
        SocketChannel socketChannel = null;  
        String requestMsg = "";  
        int count = 0;  
        if (selectionKey.isAcceptable()) {  
            //每有客户端连接，即注册通信信道为可读  
            serverSocketChannel = (ServerSocketChannel)selectionKey.channel();  
            
            socketChannel = serverSocketChannel.accept(); 
            
            socketChannel.configureBlocking(false);  
            socketChannel.register(selector, SelectionKey.OP_READ);  
            
            log.info("客户端的消息:"+socketChannel);
        }else if (selectionKey.isReadable()) {  
            socketChannel = (SocketChannel)selectionKey.channel();  
            
            rBuffer.clear();  //清理数据缓冲区
            count = socketChannel.read(rBuffer);  
            //读取数据  
            if (count > 0) {  
                rBuffer.flip();  
                requestMsg = String.valueOf(cs.decode(rBuffer).array());  
                System.out.println(rBuffer);
            }  
            String responseMsg = "已收到客户端的消息:"+requestMsg;  
            log.info("已收到客户端的消息:"+new String(requestMsg));
            log.info("已收到客户端的消息:哈希转码:"+ StringToHexUtil.convertStringToHex(requestMsg));
            
            //返回数据  
//            sBuffer = ByteBuffer.allocate(responseMsg.getBytes("UTF-8").length);  
//            sBuffer.put(responseMsg.getBytes("UTF-8"));  
//            sBuffer.flip();  
//            socketChannel.write(sBuffer);  
            socketChannel.close();  
        }  
    }  

} 